<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Working with strings</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="Windows API, Winapi, Win32, C, strings">
<meta name="description" content="In this part of the Winapi tutorial, we 
will work with strings.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Working with strings</h1>


<p>
In C language there is no string data type. A string literal in a 
program is an array of characters. Whenever we say string we mean an
array of characters. 
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<p>
We have multiple of functions for working with strings. Both in 
C runtime library (CRT) and in Windows API. First we will describe some Winapi
string functions.
</p>


<h2>The string length</h2>

<p>
One of the most common requirements is to figure out the length of the string. 
The <code>lstrlen()</code> function returns the lenght of the specified string 
in characters. It does not count the terminating null character.  
</p>

<pre>
int WINAPI lstrlenA(LPCSTR lpString);
int WINAPI lstrlenW(LPCWSTR lpString);
</pre>

<p>
The ANSI and the UNICODE functions take the string as a parameter and return
the number of characters in the string.
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

int wmain(void) 
{
  char *name = "Jane";
  wchar_t *town = L"Bratislava";

  wprintf(L"The length of the name string is %d\n", lstrlenA(name));
  wprintf(L"The town string length is %d\n", lstrlenW(town));

  return 0;
}
</pre>

<p>
We compute the length of two strings. The <code>lstrlen()</code> function
is in fact a macro to either <code>lstrlenA()</code> or <code>lstrlenW()</code>.
The first is used for ANSI strings, the second for wide strings. 
</p>

<pre class="explanation">
wprintf(L"The town string length is %d\n", lstrlenW(town));
</pre>

<p>
We print the length of the L"Bratislava" string using the <code>lstrlenW()</code>
function. 
</p>

<pre>
C:\winapi\examples2\strings\StringLength>string_length.exe
The name string length is 4
The town string length is 10
</pre>

<p>
Output of the program.
</p>


<h2>Concatenating strings</h2>

<p>
The <code>lstrcatW()</code> function appends one string to another string.
</p>

<pre>
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2);
</pre>

<p>
The first parameter is the buffer which should contain both strings. It
must be large enough to contain both of them. Including the null terminating
character. The return value is a pointer to the buffer. 
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

int main(void) 
{
  wchar_t *s1 = L"ZetCode, ";
  wchar_t *s2 = L"tutorials ";
  wchar_t *s3 = L"for ";
  wchar_t *s4 = L"programmers.\n";

  int len = lstrlenW(s1) + lstrlenW(s2) 
      + lstrlenW(s3) + lstrlenW(s4);
  wchar_t buff[len+1];
  
  lstrcpyW(buff, s1);
  lstrcatW(buff, s2);
  lstrcatW(buff, s3);
  lstrcatW(buff, s4);

  wprintf(buff);    

  return 0;
}
</pre>

<p>
In the example, we will concatenate four strings. 
</p>

<pre class="explanation">
wchar_t *s1 = L"ZetCode, ";
wchar_t *s2 = L"tutorials ";
wchar_t *s3 = L"for ";
wchar_t *s4 = L"programmers.\n";
</pre>

<p>
These are the strings that we are going to concatenate.
</p>

<pre class="explanation">
int len = lstrlenW(s1) + lstrlenW(s2) 
    + lstrlenW(s3) + lstrlenW(s4);
</pre>

<p>
We compute the length of the four strings using the <code>lstrlenW()</code>
function. 
</p>

<pre class="explanation">
wchar_t buff[len+1];
</pre>

<p>
We create a buffer to hold the final string. Note that we add 1 to include
the null character.
</p>

<pre class="explanation">
lstrcpyW(buff, s1);
</pre>

<p>
We copy the first string to the buffer using the <code>lstrcpyW()</code> 
function.
</p>

<pre class="explanation">
lstrcatW(buff, s2);
lstrcatW(buff, s3);
lstrcatW(buff, s4);
</pre>

<p>
We append the remaining strings with the <code>lstrcatW()</code> function.
</p>

<pre>
C:\winapi\examples2\strings\Cat>Cat.exe
ZetCode, tutorials for programmers.
</pre>

<p>
Output of the program.
</p>


<h2>Converting characters</h2>

<p>
We have two methods for converting characters either to uppercase or to
lowercase. The <code>CharLowerW()</code> function converts a character string 
or a single character to lowercase. The <code>CharUpperW()</code> function 
converts a character string or a single character to uppercase. 
If the operand is a character string, the function converts the characters 
in place. In other words, they are modified. 
</p>

<pre>
LPWSTR WINAPI CharLowerW(LPWSTR lpsz);
LPWSTR WINAPI CharUpperW(LPWSTR lpsz);
</pre>

<p>
The functions modify the strings in place and return a pointer to the 
modified string.
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

#pragma comment(lib, "User32.lib")

int wmain(void) 
{
  wchar_t str[] = L"Europa";

  CharLowerW(str);
  wprintf(L"%ls\n", str);

  CharUpperW(str);
  wprintf(L"%ls\n", str);    

  return 0;
}
</pre>

<p>
We have one string which we convert to lowercase and uppercase.
</p>

<pre class="explanation">
CharLowerW(str);
wprintf(L"%ls\n", str);
</pre>

<p>
We convert the str string to lowercase with the <code>CharLowerW()</code>
method. The string is modified in place.
</p>

<pre>
C:\winapi\examples2\strings\UpperLower>UpperLower.exe
europa
EUROPA
</pre>

<p>
Output of the UpperLower.exe program.
</p>


<h2>Comparing strings</h2>

<p>
We often need to compare two strings. The <code>lstrcmpW()</code> function
compares two strings. It returns 0 if the strings are equal. The comparison
is case sensitive. This means that "Cup" and "cup" are two different strings.
The <code>lstrcmpiW()</code> yields case insensitive string comparison. For
this function, "Cup" and "cup" are equal.
</p>

<pre>
int WINAPI lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2);
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2);
</pre>

<p>
The functions take two strings as parameters. The return value indicates the
equality of the strings. 0 value is returned for equal strings.
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

#define STR_EQUAL 0

int wmain(void)
{
  wchar_t *s1 = L"Strong";
  wchar_t *s2 = L"strong";
  
  if (lstrcmpW(s1, s2) == STR_EQUAL) {
      wprintf(L"%ls and %ls are equal\n", s1, s2);
  } else {
      wprintf(L"%ls and %ls are not equal\n", s1, s2);
  }

  wprintf(L"When applying case insensitive comparison:\n");
  if (lstrcmpiW(s1, s2) == STR_EQUAL) {
      wprintf(L"%ls and %ls are equal\n", s1, s2);
  } else {
      wprintf(L"%ls and %ls are not equal\n", s1, s2);
  }

  return 0;
}
</pre>

<p>
We have two strings. We compare them using both case sensitive and case 
insensitive string comparison. 
</p>

<pre class="explanation">
if (lstrcmpW(s1, s2) == STR_EQUAL) {
    wprintf(L"%ls and %ls are equal\n", s1, s2);
} else {
    wprintf(L"%ls and %ls are not equal\n", s1, s2);
}
</pre>

<p>
If the <code>lstrcmpW()</code> function returns STR_EQUAL, which is 
defined to 0, then we print to the console that the two strings are equal.
Otherwise we print that they are not equal. 
</p>

<pre>
C:\winapi\examples2\strings\Compare>Compare.exe
Strong and strong are not equal
When applying case insensitive comparison:
Strong and strong are equal
</pre>

<p>
The Compare.exe program gives the above output.
</p>


<h2>Filling a buffer</h2>

<p>
Filling a buffer with formatted data is essential in C programming.
The <code>wsprintfW()</code> function writes formatted data to the specified 
buffer.
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

#pragma comment(lib, "User32.lib")

int wmain(void)
{
  SYSTEMTIME st;
  wchar_t buff[50];

  GetLocalTime(&st);
  wsprintfW(buff, L"Today is %lu.%lu.%lu\n", st.wDay, 
      st.wMonth, st.wYear);

  wprintf(buff);

  return 0;
}
</pre>

<p>
We build a string which is filled with the current date.  
</p>

<pre class="explanation">
wchar_t buff[50];
</pre>

<p>
In this particular case we can safely assume that the string will not exceed 
50 characters. 
</p>

<pre class="explanation">
GetLocalTime(&st);
</pre>

<p>
The <code>GetLocalTime()</code> function retrieves the current local date and 
time.
</p>

<pre class="explanation">
wsprintfW(buff, L"Today is %lu.%lu.%lu\n", st.wDay, 
    st.wMonth, st.wYear);
</pre>

<p>
The <code>wsprintfW()</code> fills the buffer with a wide string. Arguments
are copied to the string according to the format specifier.
</p>

<pre class="explanation">
wprintf(buff);
</pre>

<p>
The contents of the buffes is printed to the console.
</p>

<pre>
C:\winapi\examples2\strings\Data2Buffer>Data2Buffer.exe
Today is 22.9.2012
</pre>

<p>
Output of the example.
</p>


<h2>Character types</h2>

<p>
Characters have various types. They can be digits, spaces, letters, punctuation
or control characters. 
</p>

<pre>
BOOL WINAPI GetStringTypeW(DWORD dwInfoType, LPCWSTR lpSrcStr,
    int cchSrc, LPWORD lpCharType);
</pre>

<p>
The <code>GetStringTypeW()</code> function retrieves 
character type information for the characters in the specified Unicode 
string. The first parameter is a flag specifying the info types.
</p>

<table>
<thead>
<tr><th>Flag</th><th>Meaning</th></tr>
</thead>
<tbody>
<tr><td>CT_CTYPE1</td><td>Retrieve character type information</td></tr>
<tr class="gray"><td>CT_CTYPE2</td><td>Retrieve bidirectional layout information</td></tr>
<tr><td>CT_CTYPE3</td><td>Retrieve text processing information</td></tr>
</tbody>
</table>

<div class="table">Table: Character info types</div>

<p>
The second parameter is the Unicode string for which to retrieve the 
character types. The third parameter is the size of the string. The final
parameter is a pointer to an array of 16-bit values. The length of this array 
must be large enough to receive one 16-bit value for each character in the 
source string.  
</p>

<p>
The <code>GetStringTypeW()</code> function returns a value, which is a 
combination of types. We can query a specific type with the &amp; operator.
</p>

<table>
<thead>
<tr><th>Value</th><th>Meaning</th></tr>
</thead>
<tbody>
<tr class="gray"><td>C1_DIGIT</td><td>Decimal digits</td></tr>
<tr><td>C1_SPACE</td><td>Space characters</td></tr>
<tr class="gray"><td>C1_PUNCT</td><td>Punctuation</td></tr>
<tr><td>C1_CNTRL</td><td>Control characters</td></tr>
<tr class="gray"><td>C1_ALPHA</td><td>Any linguistic character</td></tr>
</tbody>
</table>

<div class="table">Table: Partial list of character types</div>


<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

int wmain(void) 
{
  wchar_t str[] = L"7 white, 3 red roses.\n";

  int alphas = 0;
  int digits = 0;
  int spaces = 0;
  int puncts = 0;
  int contrs = 0;

  int size = lstrlenW(str);
  WORD types[size];

  BOOL rv = GetStringTypeW(CT_CTYPE1, str, size, types);

  if (!rv) {
    wprintf(L"Could not get character types (%ld)", GetLastError());
    return EXIT_FAILURE;
  }

  for (int i=0; i&lt;size; i++) {

    if (types[i] & C1_ALPHA) {
      alphas++;
    }

    if (types[i] & C1_DIGIT) {
      digits++;
    }

    if (types[i] & C1_SPACE) {
      spaces++;
    }

    if (types[i] & C1_PUNCT) {
      puncts++;
    }

    if (types[i] & C1_CNTRL) {
      contrs++;
    }
  }

  wprintf(L"There are %ld letter(s), %ld digit(s), "
    L"%ld space(s), %ld punctuation character(s), "
    L"and %ld control character(s)\n", alphas, digits, 
    spaces, puncts, contrs);  

  return 0;
}
</pre>

<p>
We have a short sentence. The <code>GetStringTypeW()</code> function is used
to determine the character types of the string.
</p>

<pre class="explanation">
wchar_t str[] = L"7 white, 3 red roses.\n";
</pre>

<p>
This is a short sentence consisting of various wide characters.
</p>

<pre class="explanation">
int alphas = 0;
int digits = 0;
int spaces = 0;
int puncts = 0;
int contrs = 0;
</pre>

<p>
These variables will be used to count letters, digits, spaces, punctuation and
control characters.
</p>

<pre class="explanation">
int size = lstrlenW(str);
WORD types[size];
</pre>

<p>
We get the size of the string and create and array of values. The size does not
include the null terminating character. We can add 1 to include it. It will 
be counted as a control character.  
</p>

<pre class="explanation">
BOOL rv = GetStringTypeW(CT_CTYPE1, str, size, types);
</pre>

<p>
We get the character types of the sentence. The types array is filled
with character type values.  
</p>

<pre class="explanation">
if (types[i] & C1_DIGIT) {
  digits++;
}
</pre>

<p>
If the value contains the <code>C1_DIGIT</code> flag, we increase the 
digits counter. 
</p>

<pre>
C:\winapi\examples2\strings\Letters>Letters.exe
There are 13 letter(s), 2 digit(s), 5 space(s), 2 punctuation character(s), and
1 control character(s)
</pre>

<p>
Output of the example.
</p>


<h2>The CRT string functions</h2>

<p>
There are also lots of string functions in the C Run-Time (CRT) library.
Many of them are duplicates to the Winapi functions. It is a matter of opinion
which types of string functions should be used. The CRT functions have some
small overhead since they call Winapi functions underneath.
</p>

<pre class="code">
#include &lt;windows.h&gt;
#include &lt;wchar.h&gt;

#define STR_EQUAL 0

int wmain(void)
{
  wchar_t str1[] = L"There are 15 pines";

  wprintf(L"The length of the string is %ld characters\n", 
    wcslen(str1));

  wchar_t buf[20];
  wcscpy(buf, L"Wuthering");
  wcscat(buf, L" heights\n");
  wprintf(buf);

  if (wcscmp(L"rain", L"rainy")== STR_EQUAL) {
    wprintf(L"rain and rainy are equal strings\n");
  } else {
    wprintf(L"rain and rainy are not equal strings\n");
  } 

  return 0;
}
</pre>

<p>
In the example we present a few string functions from the CRT library.
</p>

<pre class="explanation">
wprintf(L"The length of the string is %ld characters\n", 
  wcslen(str1));
</pre>

<p>
The <code>wcslen()</code> returns the number of characters in the string.
</p>

<pre class="explanation">
wcscpy(buf, L"Wuthering");
</pre>

<p>
The <code>wcscpy</code> copies a string to a string buffer.
</p>

<pre class="explanation">
wcscat(buf, L" heights\n");
</pre>

<p>
The <code>wcscat()</code> function appends a string to a string buffer.
</p>

<pre class="explanation">
if (wcscmp(L"rain", L"rainy")== STR_EQUAL) {
  wprintf(L"rain and rainy are equal strings\n");
} else {
  wprintf(L"rain and rainy are not equal strings\n");
} 
</pre>

<p>
The <code>wcscmp()</code> compares two string.
</p>

<pre>
C:\winapi\examples2\strings\CRTStrings>CRTStrings.exe
The length of the string is 18 characters
Wuthering heights
rain and rainy are not equal strings
</pre>

<p>
Output of the example.
</p>

                                   
<p>
In this part of the Winapi tutorial, we have worked with strings.
</p>

<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br> 


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 29, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>
